import os
import json
import logging
from typing import Dict, List, Tuple, Any, Optional


# 默认元数据配置
DEFAULT_METADATA = {
    'baseProtocol': None,
    'name': '未知协议',
    'edition': '未知',
    'description': '',
    'headerVersion': '2019'  # 默认使用2019版本
}


def load_version_metadata(version_path: str) -> Dict[str, Any]:
    """加载版本目录中的metadata.json文件
    
    Args:
        version_path: 版本目录路径
        
    Returns:
        元数据字典，包含baseProtocol、name、edition、description、headerVersion
        如果metadata.json不存在，返回默认值
    """
    metadata_file = os.path.join(version_path, 'metadata.json')
    
    if not os.path.exists(metadata_file):
        logging.warning(f"metadata.json不存在: {metadata_file}，使用默认配置")
        return DEFAULT_METADATA.copy()
    
    try:
        with open(metadata_file, 'r', encoding='utf-8') as f:
            metadata = json.load(f)
        
        # 合并默认值，确保所有必需字段都存在
        result = DEFAULT_METADATA.copy()
        result.update(metadata)
        return result
    except Exception as e:
        logging.error(f"加载metadata.json失败: {metadata_file}, 错误: {e}")
        return DEFAULT_METADATA.copy()


def get_header_version(active_profile: str, 
                       base_dir: str = os.path.join('.', 'config', 'frames')) -> str:
    """获取指定版本的header版本
    
    Args:
        active_profile: 版本标识（如"sichuan/2025"）
        base_dir: 配置文件基础目录
        
    Returns:
        "2013" 或 "2019"
    """
    if not active_profile:
        return DEFAULT_METADATA['headerVersion']
    
    version_path = os.path.join(base_dir, active_profile)
    metadata = load_version_metadata(version_path)
    return metadata.get('headerVersion', DEFAULT_METADATA['headerVersion'])


def resolve_base_protocol(active_profile: str,
                          base_dir: str = os.path.join('.', 'config', 'frames')) -> Optional[str]:
    """解析版本的基础协议
    
    Args:
        active_profile: 版本标识（如"sichuan/2025"）
        base_dir: 配置文件基础目录
        
    Returns:
        基础协议版本（如"jt808/2019"），如果没有baseProtocol则返回None
    """
    if not active_profile:
        return None
    
    version_path = os.path.join(base_dir, active_profile)
    metadata = load_version_metadata(version_path)
    return metadata.get('baseProtocol')


def list_versions(base_dir: str = os.path.join('.', 'config', 'frames')) -> Dict[str, Dict[str, object]]:
    """扫描版本目录，返回版本到信息的映射。

    返回示例：
    {
      'jt808/2019': { 
        'path': './config/frames/jt808/2019', 
        'cmds': ['0x0100','0x0102'],
        'metadata': {
          'baseProtocol': None,
          'name': 'JT/T 808-2019...',
          'edition': '2019',
          'description': '...',
          'headerVersion': '2019'
        }
      },
      'sichuan/2025': { 
        'path': './config/frames/sichuan/2025', 
        'cmds': ['0x0100','0x0102'],
        'metadata': {
          'baseProtocol': 'jt808/2019',
          'name': '四川省...',
          'edition': '2025',
          'description': '...',
          'headerVersion': '2019'
        }
      }
    }
    """
    versions: Dict[str, Dict[str, object]] = {}
    if not os.path.isdir(base_dir):
        return versions

    for standard in os.listdir(base_dir):
        std_path = os.path.join(base_dir, standard)
        if not os.path.isdir(std_path):
            continue
        for edition in os.listdir(std_path):
            ver_path = os.path.join(std_path, edition)
            if not os.path.isdir(ver_path):
                continue
            key = f"{standard}/{edition}"
            cmds: List[str] = []
            for fname in os.listdir(ver_path):
                if not fname.lower().endswith('.json'):
                    continue
                # 跳过metadata.json
                if fname.lower() == 'metadata.json':
                    continue
                stem = os.path.splitext(fname)[0]
                if stem.lower().startswith('0x') and len(stem) >= 4:
                    cmds.append(stem.lower())
            
            # 加载元数据
            metadata = load_version_metadata(ver_path)
            
            versions[key] = { 
                'path': ver_path, 
                'cmds': sorted(cmds),
                'metadata': metadata
            }
    return versions


def validate_and_get_active_profile(env_value: str | None,
                                    versions: Dict[str, Dict[str, object]],
                                    default_profile: str = 'sichuan/2025') -> str:
    """校验并返回活动版本。

    优先顺序：env_value (存在且有效) -> default_profile (存在) -> 任意可用版本(字典序最小) -> 顶层frames目录
    """
    logger = logging.getLogger(__name__)

    if env_value and env_value in versions:
        return env_value

    if env_value and env_value not in versions:
        logger.warning("环境变量JT_PROFILE='%s'不存在于版本列表，将回退到默认/可用版本", env_value)

    if default_profile in versions:
        return default_profile

    if versions:
        # 选择一个稳定顺序的可用项
        selected = sorted(versions.keys())[0]
        logger.warning("默认版本'%s'不可用，已回退到'%s'", default_profile, selected)
        return selected

    # 没有任何版本目录，回退到顶层
    logger.warning("未发现任何版本目录，回退到顶层frames目录")
    return ''


def get_frames_dir(profile: str,
                   base_dir: str = os.path.join('.', 'config', 'frames')) -> str:
    """返回指定profile的目录；若profile为空字符串，则返回base_dir本身。"""
    if profile:
        return os.path.join(base_dir, profile)
    return base_dir


def get_frame_cfg_path_for_cmd(frame_id_str: str,
                               active_profile: str,
                               base_dir: str = os.path.join('.', 'config', 'frames')) -> Tuple[str, bool]:
    """根据活动版本与指令号返回配置文件路径。

    返回: (路径, 是否命中活动版本目录)
    若活动版本目录未命中，则回退到base_dir顶层(兼容历史)。
    """
    frame_file = f"{frame_id_str.lower()}.json"
    if active_profile:
        prof_dir = get_frames_dir(active_profile, base_dir)
        prof_path = os.path.join(prof_dir, frame_file)
        if os.path.exists(prof_path):
            return prof_path, True
    # 回退顶层
    top_path = os.path.join(base_dir, frame_file)
    return top_path, False


